#include "preHeader.h"
#include "AuraObject.h"
#include "Map/MapInstance.h"
#include "Spell/Spell.h"

AuraObject::AuraObject()
: LocatableObject(TYPE_AURAOBJECT)
, m_pProto(NULL)
, m_pSpellProto(NULL)
, m_spellLevel(0)
, m_effectIndex(0)
, m_spellInstGuid(0)
, m_pCaster(NULL)
, m_pOwner(NULL)
, m_effSpellInstGuid(Spell::NewSpellInstGuid())
{
}

AuraObject::~AuraObject()
{
}

void AuraObject::SubInitLuaEnv()
{
	m_blackboard.SetActor(m_pMapInstance->L, this);
	this->binder::setfinal();
}

bool AuraObject::InitAuraObject(const AuraPrototype* pProto,
	Spell* pSpell, uint32 effectIndex, Unit* pOwner)
{
	m_pProto = pProto;
	m_pSpellProto = pSpell->GetSpellProto();
	m_spellLevel = pSpell->GetSpellLevel();
	m_effectIndex = effectIndex;
	m_spellInstGuid = pSpell->GetSpellInstGuid();
	m_pCaster = pSpell->GetCaster();;
	m_pOwner = pOwner;

	if (pProto->auraDelayEffective == 0) {
		AoiActor::SetRadius(pProto->auraEffectiveRadius);
	}

	return true;
}

void AuraObject::OnPushToWorld()
{
	if (m_pProto->auraDelayEffective != 0) {
		CreateTimerX([=]() {
			AoiActor::SetRadius(m_pProto->auraEffectiveRadius);
			m_pMapInstance->ReloadAoiActorRadiusOrder(this);
		}, m_pProto->auraDelayEffective, 1);
	}
	if (m_pProto->lifeTime != 0) {
		CreateTimerX([=]() {
			FastDisappear();
		}, m_pProto->lifeTime, 1);
	}
	LocatableObject::OnPushToWorld();
}

void AuraObject::OnDelete()
{
	m_pCaster->RemoveReferAuraObject(this);
	m_pOwner->RemoveReferAuraObject(this);
	LocatableObject::OnDelete();
}

void AuraObject::BuildCreatePacketForPlayer(INetPacket& pck, Player* pPlayer)
{
	LocatableObject::BuildCreatePacketForPlayer(pck, pPlayer);
}

void AuraObject::Update(uint64 diffTime)
{
	LocatableObject::Update(diffTime);
}

bool AuraObject::CanApplyAuraEffect(Unit* pTarget) const
{
	switch (AuraSelectType(m_pProto->auraTargetType)) {
	case AuraSelectType::Friend:
		return m_pCaster->IsFriend(pTarget);
	case AuraSelectType::Enemy:
		return m_pCaster->IsHostile(pTarget);
	case AuraSelectType::Player:
		return pTarget->IsKindOf(TYPE_PLAYER);
	case AuraSelectType::Creature:
		return pTarget->IsKindOf(TYPE_CREATURE);
	case AuraSelectType::TeamMember:
		return m_pCaster->IsType(TYPE_PLAYER) && pTarget->IsType(TYPE_PLAYER) &&
			((Player*)m_pCaster)->IsPlayTeamMember(pTarget->GetGuid());
	default:
		return false;
	}
}

void AuraObject::EnterAuraEffect(Unit* pTarget)
{
	if (m_pProto->isLeaveContinue) {
		pTarget->InterruptSpellByGuid(m_effSpellInstGuid);
	}
	Spell::ApplySpell(m_pCaster, pTarget, m_effSpellInstGuid,
		m_pProto->effectSpellID, m_pProto->effectSpellLevel,
		m_pProto->effectIndexes, true);
}

void AuraObject::LeaveAuraEffect(Unit* pTarget)
{
	pTarget->InterruptSpellByGuid(m_effSpellInstGuid);
	if (m_pProto->isLeaveContinue) {
		Spell::ApplySpell(m_pCaster, pTarget, m_effSpellInstGuid,
			m_pProto->effectSpellID, m_pProto->effectSpellLevel,
			m_pProto->effectIndexes, false);
	}
}

AuraPrototype AuraObject::ParseAuraPrototype(const char* args)
{
	AuraPrototype proto;
	TextUnpacker unpacker(args);
	unpacker >> proto.lifeTime >> proto.auraTargetType
		>> proto.auraDelayEffective >> proto.auraEffectiveRadius
		>> proto.effectSpellID >> proto.effectSpellLevel
		>> proto.effectIndexes >> proto.isFollowOwner
		>> proto.isLeaveContinue >> proto.isClientVisible;
	return proto;
}
